<?php
namespace Core;

use Exception;

class Router {
    protected $routes = [];
    protected $routeGroups = [];
    protected $container;
    protected $globalMiddleware = [];
    protected $currentRoute;
    
    public function __construct(Container $container) {
        $this->container = $container;
    }
    
    public function addRoute($method, $path, $handler, $middleware = []) {
        // 应用当前路由组的前缀和中间件
        $fullPath = $this->applyGroupPrefix($path);
        $fullMiddleware = array_merge($this->applyGroupMiddleware(), $middleware);
        
        $route = [
            'method' => strtoupper($method),
            'path' => $this->normalizePath($fullPath),
            'handler' => $handler,
            'middleware' => $fullMiddleware
        ];
        
        $this->routes[] = $route;
        $this->currentRoute = &$this->routes[count($this->routes) - 1];
        return $this;
    }
    
    // 添加 any 方法，支持所有 HTTP 方法
    public function any($path, $handler, $middleware = []) {
        $methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
        foreach ($methods as $method) {
            $this->addRoute($method, $path, $handler, $middleware);
        }
        return $this;
    }
    
    // 添加对特定 HTTP 方法的快捷方式
    public function get($path, $handler, $middleware = []) {
        return $this->addRoute('GET', $path, $handler, $middleware);
    }
    
    public function post($path, $handler, $middleware = []) {
        return $this->addRoute('POST', $path, $handler, $middleware);
    }
    
    public function put($path, $handler, $middleware = []) {
        return $this->addRoute('PUT', $path, $handler, $middleware);
    }
    
    public function delete($path, $handler, $middleware = []) {
        return $this->addRoute('DELETE', $path, $handler, $middleware);
    }
    
    public function patch($path, $handler, $middleware = []) {
        return $this->addRoute('PATCH', $path, $handler, $middleware);
    }
    
    public function options($path, $handler, $middleware = []) {
        return $this->addRoute('OPTIONS', $path, $handler, $middleware);
    }
    
    public function group($prefix, $callback, $middleware = []) {
        $this->routeGroups[] = [
            'prefix' => $this->normalizePath($prefix),
            'middleware' => $middleware
        ];
        
        call_user_func($callback, $this);
        
        array_pop($this->routeGroups);
    }
    
    public function addGlobalMiddleware($middleware) {
        $this->globalMiddleware[] = $middleware;
    }
    
    // 添加 where 方法支持路由参数约束
    public function where($constraints) {
        if ($this->currentRoute) {
            $this->currentRoute['constraints'] = $constraints;
        }
        return $this;
    }
    
    public function dispatch(Request $request) {
        $path = $request->getPath();
        $method = $request->getMethod();
        
        foreach ($this->routes as $route) {
            if ($route['method'] !== $method && $route['method'] !== 'ANY') {
                continue;
            }
            
            $pattern = $this->buildPatternFromPath($route['path'], $route['constraints'] ?? []);
            
            if (preg_match($pattern, $path, $matches)) {
                // 提取命名参数
                $params = [];
                foreach ($matches as $key => $value) {
                    if (is_string($key)) {
                        $params[$key] = $value;
                    }
                }
                
                $request->setRouteParams($params);
                
                $middleware = array_merge($this->globalMiddleware, $route['middleware']);
                
                $handler = $route['handler'];
                
                $next = function($request) use ($handler) {
                    return $this->callHandler($handler, $request);
                };
                
                foreach (array_reverse($middleware) as $mw) {
                    $next = function($request) use ($mw, $next) {
                        $middlewareInstance = $this->container->make($mw);
                        return $middlewareInstance->handle($request, $next);
                    };
                }
                
                return $next($request);
            }
        }
        
        // 如果没有找到路由，返回 404
        return Response::make()
            ->status(404)
            ->json(['error' => 'Not Found']);
    }
    
    protected function callHandler($handler, Request $request) {
        if (is_callable($handler)) {
            return $handler($request);
        }
        
        if (is_string($handler) && strpos($handler, '@') !== false) {
            list($controller, $method) = explode('@', $handler);
            $controller = "App\\Controllers\\{$controller}";
            $controllerInstance = $this->container->make($controller);
            return $controllerInstance->$method($request);
        }
        
        throw new Exception('Invalid handler');
    }
    
    protected function normalizePath($path) {
        return '/' . trim($path, '/');
    }
    
    protected function buildPatternFromPath($path, $constraints = []) {
        // 替换 {param} 为命名捕获组
        $pattern = preg_replace_callback('/\{([a-zA-Z0-9_]+)\}/', function($matches) use ($constraints) {
            $param = $matches[1];
            $regex = $constraints[$param] ?? '[a-zA-Z0-9_]+';
            return '(?P<' . $param . '>' . $regex . ')';
        }, $path);
        
        $pattern = str_replace('/', '\/', $pattern);
        return '/^' . $pattern . '$/';
    }
    
    protected function parseParams($matches) {
        $params = [];
        foreach ($matches as $key => $value) {
            if (is_string($key)) {
                $params[$key] = $value;
            }
        }
        return $params;
    }
    
    protected function applyGroupPrefix($path) {
        $prefix = '';
        foreach ($this->routeGroups as $group) {
            $prefix .= $group['prefix'];
        }
        return $prefix . $path;
    }
    
    protected function applyGroupMiddleware() {
        $middleware = [];
        foreach ($this->routeGroups as $group) {
            $middleware = array_merge($middleware, $group['middleware']);
        }
        return $middleware;
    }
}